use crate::pool;

use super::menu::Menu;
use rbatis::rbdc::db::ExecResult;
use rbatis::sql::PageRequest;
use rbatis::{crud, impl_select, impl_select_page, Page, rbdc, sql};
use rbdc::datetime::DateTime;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TbUser {
    pub id: Option<u64>,
    pub created_at: Option<DateTime>,
    pub appid: String,
    pub username: String,
    pub ver: Option<u64>,
    pub password: String,
    pub finger_l0: Option<String>,
    pub finger_l1: Option<String>,
    pub finger_l2: Option<String>,
    pub finger_l3: Option<String>,
    pub finger_l4: Option<String>,
    pub finger_r0: Option<String>,
    pub finger_r1: Option<String>,
    pub finger_r2: Option<String>,
    pub finger_r3: Option<String>,
    pub finger_r4: Option<String>,
    pub phone: Option<String>,
    pub ic: Option<String>,
    pub car: Option<String>,
    pub role_id: u64,
    pub last_login_ts: Option<DateTime>,
    pub avatar: Option<String>,
    pub name: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct User {
    pub id: u64,
    pub created_at: Option<DateTime>,
    pub appid: String,
    pub username: String,
    pub ver: Option<u64>,
    pub finger_l0: Option<String>,
    pub finger_l1: Option<String>,
    pub finger_l2: Option<String>,
    pub finger_l3: Option<String>,
    pub finger_l4: Option<String>,
    pub finger_r0: Option<String>,
    pub finger_r1: Option<String>,
    pub finger_r2: Option<String>,
    pub finger_r3: Option<String>,
    pub finger_r4: Option<String>,
    pub phone: Option<String>,
    pub ic: Option<String>,
    pub car: Option<String>,
    pub role_id: u64,
    pub last_login_ts: Option<DateTime>,
    pub avatar: Option<String>,
    pub name: Option<String>,
    pub menu_data: Option<Vec<Menu>>,
}

impl From<TbUser> for User {
    fn from(value: TbUser) -> Self {
        Self {
            id: value.id.unwrap(),
            created_at: value.created_at,
            appid: value.appid,
            username: value.username,
            ver: value.ver,
            finger_l0: value.finger_l0,
            finger_l1: value.finger_l1,
            finger_l2: value.finger_l2,
            finger_l3: value.finger_l3,
            finger_l4: value.finger_l4,
            finger_r0: value.finger_r0,
            finger_r1: value.finger_r1,
            finger_r2: value.finger_r2,
            finger_r3: value.finger_r3,
            finger_r4: value.finger_r4,
            phone: value.phone,
            ic: value.ic,
            car: value.car,
            role_id: value.role_id,
            last_login_ts: value.last_login_ts,
            avatar: value.avatar,
            name: value.name,
            menu_data: None,
        }
    }
}

crud!(TbUser {});
impl_select!(TbUser {select_by_appid_and_username(appid:&str, username:&str) -> Option => "`where appid = #{appid} and username = #{username}"});
impl_select_page!(TbUser {select_page(query: &crate::handlers::user::Get) =>
    "`where 1=1`
    if query.appid!=null && query.appid!='':
        ` and appid=#{query.appid}`
    if query.id!=null && query.id!='':
        ` and username=#{query.id}`
    if query.name!=null && query.name!='':
        ` and name like #{'%'+query.name+'%'}`
    if query.role!=null && query.role!='':
        ` and role=#{query.role}`
    if query.role==null || query.role=='':
        ` and role<>'admin'`"
});

impl TbUser {
    pub async fn get_user(username: &str) -> Result<Option<TbUser>, rbdc::Error> {
        TbUser::select_by_appid_and_username(pool!(), "10001", username).await
    }

    pub async fn update_by_id(user: &TbUser) -> Result<ExecResult, rbdc::Error> {
        TbUser::update_by_column(pool!(), user, "id").await
    }

    pub async fn get_users(
        page: &crate::common::QueryPage,
        query: &crate::handlers::user::Get,
    ) -> Result<Page<TbUser>, rbdc::Error> {
        TbUser::select_page(pool!(), &PageRequest::from(page), query).await
    }

    pub async fn get_all_users() -> Result<Vec<TbUser>, rbdc::Error> {
        TbUser::select_all(pool!()).await
    }
}
